/*
Brick And Blast, a crossplatform breakout game.
 Copyright (C) 2008-2010 Julien CLEMENT (andematunum@gmail.com)
 
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#ifndef _Ball_h_
#define _Ball_h_

/**
* file   Ball.h
* date   Ven 25 déc 2009 20:47:00 CET
* brief  TODO
*/

#include "GameObject.h"
#include "Vector2d.h"
#include <math.h>


/** TESTING ONLY */
#include <iostream>
#include <vector>
using namespace std;

struct ColliderData;
class BatPart;
class Bumper;
class Edge;

class Ball: public GameObject {
public:
  Ball () : GameObject() {
  }
  Ball (SDL_Point& initPosition,
        SDL_TextureID initTexture,
        double angle, double velocity);
  /** Calculate next position but do not perform the move.
    * Used by the collision engine. */
  virtual void calculate_next_pixel_position ();
  /** Assign a new angle after an horizontal collision occured. */
  void collide_horizontal () {
    angle_ = M_PI - angle_;
    update_angle();
  }
  /** Assign a new angle after a vertical collision occured. */
  void collide_vertical () {
    angle_ = -angle_;
    update_angle();
  }
  /** Assign a new angle after a corner collision occured. */
  void collide_corner () {
    angle_ = M_PI + angle_;
    update_angle();
  }
  /** Set the current velocity of the ball in the real space. */
  void set_velocity (double v) {
    velocity_ = v;
    set_accel_decel(1.);
    update_angle();
  }
  /** Get the current velocity of the ball in the real space. */
  double get_velocity () {
    return velocity_;
  }
  /** Set the accel/decel factor */
  void set_accel_decel (double v) {
    accel_decel_ = v;
  }
  /** Set the current position of the ball in the pixel space. */
  virtual void set_position (SDL_Point& xy);
  /** Move the ball to the specified position in the pixel space .*/
  //virtual void move_to (SDL_Point& xy);
  /** Update the ball state.
      Internally calls \sa move. */
  virtual bool update () {
    move();
    return false;
  }
  /** Move the ball in the real space. */
  void move ();

  /** Mainly used for testing */
  void set_angle(double angle) {
    angle_ = angle;
    update_angle();
    if (angle_ > 2.*M_PI) {
      cout << "Warning:  modulo is necessary for angle: " << angle_ << endl;
    }
    //cout << "Angle: " << 360.0 * angle / (2.*M_PI)<< endl;
  }
  double get_angle () {
    return angle_;
  }
  /** Manage the collision between the ball and the game area boundaries. */
  virtual bool handle_game_area_collisions ();
  void handle_collision (GameObject* obj, const ColliderData& data);
  void handle_collision (Ball* other, const ColliderData& data);
  void handle_collision (BatPart* bat, const ColliderData& data);
  void handle_collision (Bumper* bumper, const ColliderData& data);
  void handle_collision (Edge* edge, const ColliderData& data);

private:
  /** Update the angle parameters after a collision. */
  void update_angle ();

private:
  /** Position in the real space, used
      for motion physics. */
  double center_x_;
  double center_y_;
  /** Current direction angle. */
  double angle_;
  /** Current direction vectors, updated
      at each modification of the angle. */
  double dx_;
  double dy_;
  /** Current velocity. */
  double velocity_;
  /** Accel/Decel */
  double accel_decel_;
  /** List of force vectors the ball is
    * constrained by. */
  vector<Vector2d> forces_;
};

#endif

